﻿using System;
using System.Web;
using ErrorDumper.PropertyExtracting;

namespace ErrorDumper.Web.PropertyBinders {
    public class HttpContextPropertyBinder : IExceptionPropertyExtractor {
        public void ExtractProperties(
            ref ExceptionPropertyCollection properties, object instance) {

            var context = instance as HttpContextBase;
            if (context == null) {
                var sysContext = instance as HttpContext;
                if (sysContext != null)
                    context = new HttpContextWrapper(sysContext);
                else
                    return;
            }

            if (properties == null)
                properties = new ExceptionPropertyCollection();

            var request = Resolve(() => context.Request);
            if (request != null) {
                Write(properties, "RequestUserHostAddress", () => request.UserHostAddress);
                Write(properties, "RequestUserHostName", () => request.UserHostName);
                Write(properties, "RequestUserAgent", () => request.UserAgent);
                Write(properties, "RequestUrlReferrer",
                    () => request.UrlReferrer != null ? request.UrlReferrer.OriginalString : null);
                Write(properties, "RequestTotalBytes", () => request.TotalBytes);
                Write(properties, "RequestContentLength", () => request.ContentLength);
                Write(properties, "RequestContentType", () => request.ContentType);
                Write(properties, "RequestHttpMethod", () => request.HttpMethod);
                Write(properties, "RequestUrl", () => request.RawUrl);
                Write(properties, "RequestIsLocal", () => request.IsLocal);
                Write(properties, "RequestIsSecureConnection", () => request.IsSecureConnection);
                Write(properties, "RequestPath", () => request.Path);
                Write(properties, "RequestQueryString", () => request.QueryString);
                Write(properties, "RequestFilePath", () => request.FilePath);
            }

            var response = Resolve(() => context.Response);
            if (response != null) {
                Write(properties, "ResponseStatusCode", () => response.StatusCode);
                Write(properties, "ResponseSubStatusCode", () => response.SubStatusCode);
                Write(properties, "ResponseStatus", () => response.Status);
                Write(properties, "ResponseStatusDescriptions", () => response.StatusDescription);
                Write(properties, "ResponseRedirectLocation", () => response.RedirectLocation);
                Write(properties, "ResponseContentType", () => response.ContentType);
                Write(properties, "ResponseCharset", () => response.Charset);
                Write(properties, "ResponseExpires", () => response.Expires);
                Write(properties, "ResponseExpiresAbsolute", () => response.ExpiresAbsolute.ToString("s"));
            }

            var user = Resolve(() => context.User);
            if (user != null) {
                Write(properties, "UserIsAuthenticated", () => user.Identity.IsAuthenticated);
                Write(properties, "UserName", () => user.Identity.Name);
            }
        }

        private static T Resolve<T>(Func<T> resolver) {
            try { return resolver(); }
            catch { return default(T); }
        }

        private static void Write<T>(ExceptionPropertyCollection properties, string name, Func<T> resolver) {
            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException("name");
            if (properties.Contains(name))
                return;
            string value;
            try { value = Convert.ToString(resolver()); }
            catch { return; }
            if (string.IsNullOrWhiteSpace(value))
                properties[name] = value;
        }
    }
}